package main

import "fmt"

func main() {
	game1 := NewPokerGame()
	game2 := NewPokerGame()
	fmt.Println(game2.Cards[1] == game1.Cards[1])
}

var pokerCards = map[int]*Card{
	1: {
		Name:  "A",
		Color: "红",
	},
	2: {
		Name:  "A",
		Color: "黑",
	},
}

type Card struct {
	Name  string
	Color string
}

type PokerGame struct {
	Cards map[int]*Card
}

func NewPokerGame() *PokerGame {
	board := &PokerGame{Cards: map[int]*Card{}}
	for id := range pokerCards {
		board.Cards[id] = pokerCards[id]
	}
	return board
}

/*
享元模式的结构中有一下几个角色：

Context：上下文或者叫做情景类，包含原始对象中各不相同的外在状态。 情景与享元对象组合在一起就能表示原始对象的全部状态。调用享元方法的参数由情景类提供，也可将行为移动到情景类中， 然后将连入的享元作为单纯的数据对象。
Flyweight：享元类，包含原始对象中部分能在多个对象中共享的状态。 同一享元对象可在许多不同情景中使用。 享元中存储的状态被称为 “内在状态”。 传递给享元方法的状态被称为 “外在状态”。
FlyweightFactory：享元工厂，会对已有享元的缓存池进行管理。 有了工厂后， 客户端就无需直接创建享元， 它们只需调用工厂并向其传递目标享元的一些内在状态即可。 工厂会根据参数在之前已创建的享元中进行查找， 如果找到满足条件的享元就将其返回； 如果没有找到就根据参数新建享元。
*/

/*
享元模式其实是对象池的一种应用，在应用该模式之前， 我们需要确定程序中确实存在着大量拥有相同状态（字段）的相似对象同时占用内存的问题。

享元模式的优点是能减少对象的创建，降低内存中对象的数量，降低系统的内存，提高效率。其缺点是 我们在写程序时需要关注内、外部状态，关注线程安全问题，使系统、程序的逻辑复杂化。

所以在使用的时候我们需要综合考虑，确定系统存在大量相似对象占用内村过多的问题，这些对象的一些特征字段也确实能提炼成不可变对象作为享元让外部对象进行引用，再考虑使用该模式。
*/
